import { AlignType, ClassName, Events } from "@/Constants";
import { Utils } from "../../utils";
import { IPoint, IPixelPos } from "../../Interface";
import Feature from "../Feature";
import Rect from "./Rect";

// 图片/视频, img设置宽高需要监听 LOADED 事件再设置
class Img extends Rect {

    static MaxByte = 500000  // 限制最大传入图片的大小

    domElement: HTMLImageElement | null = null;  // 图片/视频的dom元素
    _src: string | undefined // 图片/视频的地址
    get src() { return this._src }
    set src(val) {
        this._src = val;
        if (val) this.setImg(val)
    }
    _quality: number = 1 // 图片压缩 0-1, 等于1,几乎没压缩
    get quality() { return this._quality }
    set quality(val) {
        this._quality = val;
        if (this.src) this.setImg(this.src)
    }

    /**
     * @param src 如果是html标签就传入.src属性, 如果是base64直接传入, 
     */
    constructor(src: string | undefined, x: number = 0, y: number = 0, width: number = 100, quality = .5) {   // 相对坐标
        super(x, y, width, 0);
        this.quality = quality;
        this.className = ClassName.IMG;
        this.strokeStyle = "transparent"
        if (src) this.setImg(src, width)
    }

    setImg(src: string, width: number = this.size.width, height?: number) {
        const setImage = (src: string, width: number = this.size.width, height?: number) => {
            if (src.endsWith('.svg') || src.endsWith('.png') || src.endsWith('.jpg') || src.endsWith('.jfif') || src.startsWith("data:image/png;") || src.startsWith("data:image/jpeg;") || src.startsWith("data:image/jfif;")) {
                this.domElement = new Image();
                this.domElement.src = this._src = src;
                if (!height) {
                    this.domElement.onload = () => {
                        const domElement = this.domElement as HTMLImageElement;
                        const height = (domElement.height / domElement.width) * width;
                        this.setSize(width, height)
                        this.dispatch(new CustomEvent(Events.LOADED, { detail: {} }))
                    }
                    this.domElement.onerror = () => {
                        throw new Error("图片加载错误");
                    }
                }
            } else {
                throw "src参数错误!"
            }
        }
        if (encodeURIComponent(src).replace(/%../g, "x").length > Img.MaxByte) {
            // throw "只支持0.5M一下的文件!"
            Utils.compressImage(src, this.quality).then(newSrc => {
                setImage(newSrc, width, height)
            })
        } else {
            setImage(src, width, height)
        }
    }

    override draw(ctx: CanvasRenderingContext2D, pointArr: IPixelPos[], lineWidth: number, lineDashArr: number[]) {
        const path = super.draw(ctx, pointArr, lineWidth, lineDashArr);
        if (this.domElement) {
            const { width, height, leftTop } = this.getBboxSize(pointArr);
            ctx.save();
            path && ctx.clip(path);   // 放在旋转前面
            this.rotateCtx(ctx, Feature.getCenterPos(pointArr));
            ctx.drawImage(this.domElement, leftTop.x, leftTop.y, width, height);
            ctx.restore();
        }
        return path;
    }
 
    override revert(direction: AlignType, center?: IPoint, isParent = true) {
        const offscreenCanvas = document.createElement('canvas');
        if (this.domElement) {
            offscreenCanvas.width = this.domElement.width;
            offscreenCanvas.height = this.domElement.height;
            // 获取离屏Canvas的2D渲染上下文  
            const ctx = offscreenCanvas.getContext('2d') as CanvasRenderingContext2D;
            // 镜像反转
            switch (direction) {
                case AlignType.HORIZONAL:
                    ctx.scale(-1, 1);
                    ctx.drawImage(this.domElement, -offscreenCanvas.width, 0);
                    break;
                case AlignType.VERTICAL:
                    ctx.scale(1, -1);
                    ctx.drawImage(this.domElement, 0, -offscreenCanvas.height);
                    break;
                default:
                    break;
            }
            this.src = offscreenCanvas.toDataURL();
            const image = new Image();
            image.src = this.src;
            image.onload = () => {
                this.domElement = image;
                super.revert(direction, center, isParent)
            }
        }
    }

    override getSvg(pointArr: IPixelPos[] = [], lineWidth: number = 1) {
        const { width, height, leftTop } = this.getBboxSize(pointArr);
        const svgStr = super.getSvg(pointArr, lineWidth);
        const center = Feature.getCenterPos(pointArr);
        const id = Utils.getUuid();
        return svgStr + `
        <g clip-path="url(#${id})">
            <image href="${this.src}"
            transform="translate(${center.x} ${center.y}) rotate(${this.angle}) translate(-${center.x} -${center.y})"
            x="${leftTop.x}" y="${leftTop.y}"
            width="${width}" height="${height}"
            opacity="${this.opacity}"/>
        </g>
        <defs>
            <clipPath id="${id}" clipPathUnits="userSpaceOnUse">
                ${svgStr}
            </clipPath>
        </defs>
        `
    }
}

export default Img;